import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router';
import Login from '@/views/LoginView.vue'; // 登录组件
import Found404 from '@/components/404View.vue'; // 404组件
import loadingDialog from '@/api/common/loading';
//如果要在router中使用pinia，必须按照如下的方式进行导入和初始化
import pinia from '@/stores/pinia';
import { useAuthStore } from '@/stores/auth';
const authStore = useAuthStore(pinia);

//ljy修改了vite创建的路由结构，将路由数组单独拿出来，以便后面进行路由拼接
const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: 'login'
  },
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
    path: '/backstage',
    name: 'backstage',
    component: () => import('@/views/IndexView.vue'),
    meta: {
      title: '主页'
    },
    children: [
      // 使用 children 属性，实现子路由，同时，子路由的 path 前面，不要带 / ，否则永远以根路径开始请求，这样不方便我们用户去理解URL地址
      {
        path: '', // 默认子组件首页
        name: 'main',
        component: () => import('@/views/index/MainView.vue'),
        meta: {
          title: '主界面'
        }
      },
      {
        path: 'user',
        // path: '/backstage/user',
        name: 'user',
        component: () => import('@/views/page/authority/user/IndexView.vue'),
        meta: {
          title: '个人用户'
        }
      },
      {
        path: '404',
        name: '404',
        component: Found404
      }
    ]
  }
];
//创建路由
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
});

//下面是动态路由处理

// 定义一个路由对象，用于处理的路由路径不存在的情形。
// 如果要跳转的路由不存在，则跳转到404页面。因为该路由要放在最后，所以每次生成新的路由对象时都需要添加到最后
const NotFoundRoute = {
  path: '/:pathMatch(.*)',
  name: 'NotFound',
  redirect: '/backstage/404'
};

// // 拼接生成路由数据，只对菜单对象进行生成
// const createRoutesData = (permissions: Permission[], rootName?: string): RouteRecordRaw[] => {
//   console.log(9);
//   // parentRouteName表示上级路由的name属性，用于插入子路由
//   let parentRouteName = 'backstage'; // 默认的上级路由
//   if (typeof rootName !== 'undefined') {
//     // 如果传入了上级路由的名字
//     parentRouteName = rootName;
//   }
//   // 定义要添加的动态路由数组
//   const routesNew = <RouteRecordRaw[]>[];
//   // 遍历后端传递过来的权限信息，然后生成动态路由对象
//   permissions.forEach((permission: Permission) => {
//     if (permission.type === 1) {
//       // 只对菜单对象生成路由
//       const routeNew: RouteRecordRaw = {
//         redirect: permission.redirect,
//         path: permission.route,
//         // name: permission.component, //  自定义的容器名称，则用自定义的
//         name: permission.component ? permission.component : permission.name, //  如果没有自定义的容器名称，则用自定义的
//         meta: {
//           title: permission.name, // 路由的名称，用于导航路径
//           requiresAuth: permission.requireAuth, // 是否要求登录后才能访问
//           parentRouteName
//           // component: EmptyLayer,
//         }
//       };
//       // 设置组件的component
//       if (permission.path) {
//         // 如果组件的路径存在
//         //Object.defineProperty()方法来为对象添加新的属性，这个方法接受三个参数：目标对象、要定义或修改的属性名称以及一个描述符对象，描述符对象包含以下属性：
//         Object.defineProperty(routeNew, 'component', {
//           //加/* @vite-ignore */的原因如下，因为控制台提示
//           //for supported dynamic import formats. If this is intended to be left as-is, you can use the /* @vite-ignore */ comment inside the import() call to suppress this warning.
//           value: () => import(/* @vite-ignore */ `@/views${permission.path}`), // 设置属性值
//           writable: true, // 允许修改属性值
//           enumerable: true, // 允许通过for...in循环遍历属性
//           configurable: true // 允许删除属性或修改其特性
//         });
//       } else {
//         // 如果组件路径不存在。则有两种情况：1.正常情况是父容器，那么component不能为空；2.组件暂时未开发，只填写了路由的菜单
//         if (permission.children) {
//           // 如果还有子组件,说明是父组件。因为要放子组件进去，所以该组件设置为EmptyLayer组件（自定义）。否则会报错
//           Object.defineProperty(routeNew, 'component', {
//             value: { render: (c: (arg0: string) => any) => c('router-view') }, //父路由没有component时用这个代替，否则打开子组件会显示为空。; // 不能直接使用包含@或是@/符号的动态变量，因此这里要拆分
//             writable: true, // 允许修改属性值
//             enumerable: true, // 允许通过for...in循环遍历属性
//             configurable: true // 允许删除属性或修改其特性
//           });
//         }
//         // else { // 如果没有子组件，说明可能是没有组件地址的菜单（开发中）
//         //   routeNew.redirect = '/backstage/404';
//         //   // routeNew.component = Found404;
//         // }
//       }
//       if (permission.url) {
//         // 如果有连接地址，则让直接执行跳转
//         routeNew.beforeEnter = () => {
//           window.location.href = permission.url;
//         };
//       }
//       routesNew.push(routeNew);
//       if (permission.children && permission.children.length > 0) {
//         // 如果还有子组件
//         // 递归处理子路由的component
//         routesNew.push(...createRoutesData(permission.children, permission.component));
//       }
//     }
//   });
//   return routesNew;
// };

// 重置路由，主要用于用户注销或过期时的路由重置。
// 说明：因为router没有提供相关的重置方法，网上的方法在router4中又无效或是不符合eslint的规则（例如将router对象修改为let类型），刷新页面显得太row，因此选择手动删除
// 重置路由的要求：因为router.removeRoute是根据组件的name属性来删除的，因此后端必须为所有菜单都设置组件名称，且不应该重复。
const resetRouter = () => {
  // console.log('重置路由');
  // console.log('移除前');
  // console.log(router.getRoutes());
  // 获取拼接后的路由数据
  const data = authStore.getRoutes();
  // 删除原来动态添加的路由
  if (data && data.length > 0) {
    // 如果原来存储有路由信息
    // 遍历删除动态路由信息
    data.forEach((routeRaw: RouteRecordRaw) => {
      // console.log(`移除${String(routeRaw.name)}`);
      router.removeRoute(routeRaw.name!);
    });
  }
  // 手动删除路径不存在时的默认路由
  if (router.hasRoute(NotFoundRoute.name)) {
    router.removeRoute(NotFoundRoute.name);
  }
  // 注销本地存储的路由信息
  authStore.handleLogoutSuccess();
};

// 定义加载组件
const { startLoading, endLoading } = loadingDialog('正在组建菜单中，请稍后...');
// 核心业务：对动态路由进行总处理，在每次路由跳转前触发
router.beforeEach(async (to, from) => {
  if (from.path === '/login' && to.path !== '/login') {
    // 只有从登录界面跳转到其他界面，才会出现组建菜单的加载框
    startLoading();
  }
  // 将路由节点信息存入store，to.matched获取当前路由的每个路由节点的完整信息
  authStore.setRouteMatched(to.matched);
  // 判断要跳转的路由是否原来已经存在。用于处理router官方文档中说明的中因跳转的权限是刚生成时，需要重定向路由的判定状态。
  const existRoute = router.hasRoute(to.name as string);
  if (to.path === '/login') {
    // 如果要跳转的登录页面，在手动注销或是超时在axios配置中被自动跳转到登录页面
    if (authStore.getToken() != null) {
      // 如果token还存在，说明不是直接从注销页面跳转，此时跳回登录后台首页，即不允许跳转到登录页面（业务设定,用户体验感因人而异）
      return '/backstage'; // 跳转到后台主界面
    } else {
      // 如果token已经不存在，说明已经注销或失效
      // 重置路由，移除所有登录用户的信息
      resetRouter();
    }
  } else {
    // 如果是其他路径
    if (authStore.getToken == null) {
      // 如果token不存在，说明没有登录,则直接调转到登录页面
      // 重置路由，移除所有登录用户的信息
      resetRouter();
      return '/login'; // 跳到登录页面
    } else {
      // 如果已经登录
      if (authStore.getMenus().length === 0) {
        // 如果数组为空，说明该页面刚刚刷新
        // 重新在服务端加载路由信息
        await authStore.getMenusFromRemote();
        // 获取拼接后的路由数据
        const data = authStore.getRoutes();
        // 动态添加路由
        data.forEach((routeRaw: RouteRecordRaw) => {
          // 添加在路由，为了考虑面包屑导航的路由能和菜单一致，要加上父容器子容器
          router.addRoute(routeRaw.meta!.parentRouteName!, routeRaw);
        });
        // 将404路由添加到最后
        router.addRoute(NotFoundRoute);
        // 打印组建完成后的动态路由
        // console.log(router.getRoutes());
        if (!existRoute) {
          // 如果要跳转的路由原来不存在，说明路由是本次动态添加的，此时重新定位一次（这会导致访问2次），让刚添加的路由生效
          return to.fullPath;
        }
      }
    }
  }
  // 关闭加载框
  endLoading();
  return true;
});

export default router;
